import urllib


from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema, no_body
from rest_framework import status

from api import permissions, exceptions, paginations
from api.harbor import HarborManager
from api.views_v1.views import check_authenticated_or_bucket_token, rand_share_code, str_to_int_or_default
from utils.view import CustomGenericViewSet
from django.utils.translation import gettext_lazy, gettext as _
from rest_framework.response import Response
from django.urls import reverse as django_reverse
from rest_framework.serializers import Serializer
from rest_framework import parsers


class V2ShareObjViewSet(CustomGenericViewSet):

    """ v2 share api 接口 """

    queryset = {}
    permission_classes = [permissions.IsAuthenticatedOrBucketToken]
    lookup_field = 'objpath'
    lookup_value_regex = '.+'
    parser_classes = (parsers.MultiPartParser, parsers.FormParser)


    @swagger_auto_schema(
        operation_summary=gettext_lazy('v2对象共享或私有权限设置'),
        manual_parameters=[
            openapi.Parameter(
                name='share', in_=openapi.IN_QUERY,
                type=openapi.TYPE_INTEGER,
                description=gettext_lazy("分享访问权限，0（不分享禁止访问），1（分享只读），2（分享可读可写）"),
                required=True
            ),
            openapi.Parameter(
                name='share_type', in_=openapi.IN_QUERY,
                type=openapi.TYPE_STRING,
                description=gettext_lazy("分享类型，0（无， share 必须时0），1（密码），2（限时），3（密码+限时）"),
                required=True
            ),
            openapi.Parameter(
                name='days', in_=openapi.IN_QUERY,
                type=openapi.TYPE_INTEGER,
                description=gettext_lazy("对象公开分享天数(share!=0时有效)，0表示永久公开，负数表示不公开，默认为0"),
                required=False
            ),
            openapi.Parameter(
                name='password', in_=openapi.IN_QUERY,
                type=openapi.TYPE_STRING,
                description=gettext_lazy("分享密码，此参数不存在，不设密码；可指定4-8字符；若为空，随机分配密码"),
                required=False
            ),

        ],
        responses={
            status.HTTP_200_OK: """
                {
                  "code": 200,
                  "code_text": "对象共享权限设置成功",
                  "share": 1,
                  "days": 0,
                  "share_uri": "http://xxx/s/bucket-test/1499.txt",
                  "share_code": "",
                  "access_code": 1,
                  "share_endtime": "2025-08-17T02:01:53.245689Z",
                  "share_starttime": "2025-08-11T02:38:31.310906Z",
                  "share_type": 1,
                  "share_url_new": ""
                }     
            """
        }
    )
    def partial_update(self, request, *args, **kwargs):
        """

            >>
                {
                  "code": 200,
                  "code_text": "对象共享权限设置成功",
                  "share": 1,
                  "days": 0,
                  "share_uri": "http://xxx/s/bucket-test/1499.txt",  # 密码共享链接
                  "share_code": "",  # 共享密码
                  "access_code": 1,
                  "share_endtime": "2025-08-17T02:01:53.245689Z",
                  "share_starttime": "2025-08-11T02:38:31.310906Z",
                  "share_type": 1,   # 共享类型
                  "share_url_new": ""  # 限时共享链接
                }
        """
        bucket_name = kwargs.get('bucket_name', '')
        objpath = kwargs.get(self.lookup_field, '')
        pw = request.query_params.get('password', None)

        try:
            check_authenticated_or_bucket_token(request, bucket_name=bucket_name, act='write', view=self)
        except exceptions.Error as exc:
            return Response(data=exc.err_data(), status=exc.status_code)

        if pw:  # 指定密码
            if not (4 <= len(pw) <= 8):
                return Response(data={'code': 400, 'code_text': _('password参数长度为4-8个字符')},
                                status=status.HTTP_400_BAD_REQUEST)
            password = pw
        elif pw is None:  # 不设密码
            password = ''
        else:  # 随机分配密码
            password = rand_share_code()

        days = str_to_int_or_default(request.query_params.get('days', 0), None)
        if days is None:
            return Response(data={'code': 400, 'code_text': _('days参数有误')}, status=status.HTTP_400_BAD_REQUEST)

        share = request.query_params.get('share', None)
        if share is None:
            return Response(data={'code': 400, 'code_text': _('缺少share参数')}, status=status.HTTP_400_BAD_REQUEST)

        share = str_to_int_or_default(share, -1)
        if share not in [0, 1, 2]:
            return Response(data={'code': 400, 'code_text': _('share参数有误')}, status=status.HTTP_400_BAD_REQUEST)

        share_type = request.query_params.get('share_type', None)
        if share_type is None:
            return Response(data={'code': 400, 'code_text': _('缺少share_type参数')}, status=status.HTTP_400_BAD_REQUEST)

        share_type = str_to_int_or_default(share_type, -1)
        if share_type not in [0, 1, 2, 3]:
            return Response(data={'code': 400, 'code_text': _('share_type参数有误')}, status=status.HTTP_400_BAD_REQUEST)

        if share == 0 and share_type != 0:
            return Response(data={'code': 400, 'code_text': _('share_type参数有误')}, status=status.HTTP_400_BAD_REQUEST)

        hmanager = HarborManager()
        try:
            ok, access_code, obj = hmanager.share_object(
                bucket_name=bucket_name, obj_path=objpath, share=share,
                days=days, password=password, user=request.user)
        except exceptions.HarborError as e:
            return Response(data=e.err_data_old(), status=e.status_code)

        if not ok:
            return Response(data={'code': 500, 'code_text': _('对象共享权限设置失败')},
                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        if not obj.json_tags:
            obj.json_tags = {}

        obj.json_tags.update({'share_type': share_type})
        obj.save(update_fields=['json_tags'])

        share_uri = django_reverse('s:obs-detail', kwargs={'objpath': f'{bucket_name}/{objpath}'})
        # if password:
        #     share_uri = f'{share_uri}?p={password}'
        share_uri = request.build_absolute_uri(share_uri)
        share_uri = urllib.parse.unquote(share_uri)
        data = {
            'code': 200,
            'code_text': _('对象共享权限设置成功'),
            'share': share,
            'days': days,
            'share_uri': share_uri if share != 0 else '',
            'share_code': password if password else '',
            'access_code': access_code,
            'share_endtime':obj.set,
            'share_starttime': obj.sst,
            'share_type': share_type,
            'share_url_new': '',
        }

        if share_type and share_type in [2, 3]:
        # if obj.stl and (share != 0) or password and obj.stl:   # 共享时间为True 或 有密码 访问路径修改 /s/ -> /t/
            share_url_new = share_uri.replace('/s/', '/t/', 1)
            data['share_url_new'] = share_url_new

        return Response(data=data, status=status.HTTP_200_OK)

    def get_serializer_class(self):
        """
        Return the class to use for the serializer.
        Defaults to using `self.serializer_class`.
        Custom serializer_class
        """
        # if self.action == 'create_detail':
        #     return serializers.ObjPutSerializer
        # elif self.action == 'update':
        #     return serializers.ObjPutFileSerializer
        return Serializer



class V2ShareDirViewSet(CustomGenericViewSet):

    """ v2 share api 接口 """

    queryset = []
    permission_classes = [permissions.IsAuthenticatedOrBucketToken]
    lookup_field = 'dirpath'
    lookup_value_regex = '.+'
    pagination_class = paginations.BucketFileLimitOffsetPagination


    @swagger_auto_schema(
        operation_summary=gettext_lazy('v2设置目录访问权限'),
        request_body=no_body,
        manual_parameters=[
            openapi.Parameter(
                name='dirpath', in_=openapi.IN_PATH,
                type=openapi.TYPE_STRING,
                description=gettext_lazy("目录绝对路径"),
                required=True
            ),
            openapi.Parameter(
                name='share', in_=openapi.IN_QUERY,
                type=openapi.TYPE_INTEGER,
                description=gettext_lazy("用于设置目录访问权限, 0（私有），1(公有只读)，2(公有可读可写)"),
                required=True
            ),
            openapi.Parameter(
                name='days', in_=openapi.IN_QUERY,
                type=openapi.TYPE_INTEGER,
                description=gettext_lazy("公开分享天数(share=1或2时有效)，0表示永久公开，负数表示不公开，默认为0"),
                required=False
            ),
            openapi.Parameter(
                name='password', in_=openapi.IN_QUERY,
                type=openapi.TYPE_STRING,
                description=gettext_lazy("分享密码，此参数不存在，不设密码；可指定4-8字符；若为空，随机分配密码"),
                required=False
            ),
            openapi.Parameter(
                name='share_type', in_=openapi.IN_QUERY,
                type=openapi.TYPE_STRING,
                description=gettext_lazy("分享类型，0（无， share 必须时0），1（密码），2（限时），3（密码+限时）"),
                required=True
            ),
        ],
        responses={
            status.HTTP_200_OK: """
                {
                  "code": 200,
                  "code_text": "设置目录权限成功",
                  "share": "http://xxx/s/bucket-test/awfwe/",
                  "share_code": "",
                  "access_code": 1,
                  "share_endtime": "2025-09-03T02:12:37.630914Z",
                  "share_starttime": "2025-08-11T02:27:31.990704Z",
                  "share_type": 2,  
                  "share_url_new": "" 
                }
            """
        }
    )
    def partial_update(self, request, *args, **kwargs):
        """
        设置目录访问权限


            >>Http Code: 状态码200:
                {
                  "code": 200,
                  "code_text": "设置目录权限成功",
                  "share": "http://xxx/s/bucket-test/awfwe/",  # 密码共享
                  "share_code": "",  # 共享密码
                  "access_code": 1,
                  "share_endtime": "2025-09-03T02:12:37.630914Z",
                  "share_starttime": "2025-08-11T02:27:31.990704Z",
                  "share_type": 2,   # 共享类型
                  "share_url_new": ""   # 限时共享路径
                }

            >>Http Code: 400 401 403 404 500
                {
                    "code": "NoSuchKey",   // NoSuchBucket、AccessDenied、BadRequest、BucketLockWrite
                    "code_text": ""
                }
        """
        bucket_name = kwargs.get('bucket_name', '')

        try:
            check_authenticated_or_bucket_token(request, bucket_name=bucket_name, act='write', view=self)
        except exceptions.Error as exc:
            return Response(data={'code': exc.code, 'code_text': exc.message}, status=exc.status_code)

        dirpath = kwargs.get(self.lookup_field, '')
        days = str_to_int_or_default(request.query_params.get('days', 0), 0)
        share = str_to_int_or_default(request.query_params.get('share', ''), -1)
        pw = request.query_params.get('password', None)

        if pw:  # 指定密码
            if not (4 <= len(pw) <= 8):
                return Response(data={'code': 400, 'code_text': _('password参数长度为4-8个字符')},
                                status=status.HTTP_400_BAD_REQUEST)
            password = pw
        elif pw is None:  # 不设密码
            password = ''
        else:  # 随机分配密码
            password = rand_share_code()

        if share not in [0, 1, 2]:
            return Response(data={'code': 400, 'code_text': _('share参数有误')}, status=status.HTTP_400_BAD_REQUEST)

        share_type = request.query_params.get('share_type', None)
        if share_type is None:
            return Response(data={'code': 400, 'code_text': _('缺少share_type参数')}, status=status.HTTP_400_BAD_REQUEST)

        share_type = str_to_int_or_default(share_type, -1)
        if share_type not in [0, 1, 2, 3]:
            return Response(data={'code': 400, 'code_text': _('share_type参数有误')}, status=status.HTTP_400_BAD_REQUEST)

        if share == 0 and share_type != 0:
            return Response(data={'code': 400, 'code_text': _('share_type参数有误')}, status=status.HTTP_400_BAD_REQUEST)

        h_manager = HarborManager()
        try:
            ok, access_code, obj = h_manager.share_dir(bucket_name=bucket_name, path=dirpath,
                                                  share=share, days=days, password=password, user=request.user)
        except exceptions.HarborError as e:
            return Response(data=e.err_data_old(), status=e.status_code)

        if not ok:
            return Response(data={'code': 400, 'code_text': _('设置目录权限失败')}, status=status.HTTP_400_BAD_REQUEST)

        if not obj.json_tags:
            obj.json_tags = {}

        obj.json_tags.update({'share_type': share_type})
        obj.save(update_fields=['json_tags'])

        share_base = f'{bucket_name}/{dirpath}'
        share_url = django_reverse('s:share-view', kwargs={'share_base': share_base})
        share_url = request.build_absolute_uri(share_url)
        share_url = urllib.parse.unquote(share_url)

        data = {'code': 200, 'code_text': _('设置目录权限成功'),
                              'share': share_url, 'share_code': password,
                              'access_code': access_code,
                              'share_endtime': obj.set,
                              'share_starttime': obj.sst,
                              'share_type': share_type,
                              'share_url_new': '',
                              }
        if share_type and share_type in [2, 3]:
        # if obj.stl and (share != 0) or password and obj.stl:   # 共享时间为True 或 有密码 访问路径修改 /s/ -> /t/
            share_url_new = share_url.replace('/s/', '/t/', 1)
            data['share_url_new'] = share_url_new

        return Response(data=data, status=status.HTTP_200_OK)


    def get_serializer_class(self):
        """
        Return the class to use for the serializer.
        Defaults to using `self.serializer_class`.
        Custom serializer_class
        """
        # if self.action == 'create_detail':
        #     return serializers.ObjPutSerializer
        # elif self.action == 'update':
        #     return serializers.ObjPutFileSerializer
        return Serializer